03. DDPG: 行动者

深度确定性策略梯度 (DDPG)

你可以使用很多种不同的算法来设计智能体,只要它适合连续状态和动作空间即可。一种热门方法是深度确定性策略梯度,简称 DDPG。它实际上是一种行动者-评论者方法,但是关键在于底层的策略函数本身确定性函数,从外部添加了一些噪点,以便采取的动作具有理想的随机性。

我们来实现原始论文中给出的算法:

Lillicrap, Timothy P等,2015. 深度强化学习连续控制. [pdf]

可以使用最现代的深度学习库(例如 Keras 或 TensorFlow)实现该算法的两大组件 - 行动者和评论者网络。

DDPG:行动者(策略)模型

以下是使用 Keras 定义的一个非常简单的行动者模型。

from keras import layers, models, optimizers
from keras import backend as K

class Actor:
    """Actor (Policy) Model."""

    def __init__(self, state_size, action_size, action_low, action_high):
        """Initialize parameters and build model.

        Params
        ======
            state_size (int): Dimension of each state
            action_size (int): Dimension of each action
            action_low (array): Min value of each action dimension
            action_high (array): Max value of each action dimension
        """
        self.state_size = state_size
        self.action_size = action_size
        self.action_low = action_low
        self.action_high = action_high
        self.action_range = self.action_high - self.action_low

        # Initialize any other variables here

        self.build_model()

    def build_model(self):
        """Build an actor (policy) network that maps states -> actions."""
        # Define input layer (states)
        states = layers.Input(shape=(self.state_size,), name='states')

        # Add hidden layers
        net = layers.Dense(units=32, activation='relu')(states)
        net = layers.Dense(units=64, activation='relu')(net)
        net = layers.Dense(units=32, activation='relu')(net)

        # Try different layer sizes, activations, add batch normalization, regularizers, etc.

        # Add final output layer with sigmoid activation
        raw_actions = layers.Dense(units=self.action_size, activation='sigmoid',
            name='raw_actions')(net)

        # Scale [0, 1] output for each action dimension to proper range
        actions = layers.Lambda(lambda x: (x * self.action_range) + self.action_low,
            name='actions')(raw_actions)

        # Create Keras model
        self.model = models.Model(inputs=states, outputs=actions)

        # Define loss function using action value (Q value) gradients
        action_gradients = layers.Input(shape=(self.action_size,))
        loss = K.mean(-action_gradients * actions)

        # Incorporate any additional losses here (e.g. from regularizers)

        # Define optimizer and training function
        optimizer = optimizers.Adam()
        updates_op = optimizer.get_updates(params=self.model.trainable_weights, loss=loss)
        self.train_fn = K.function(
            inputs=[self.model.input, action_gradients, K.learning_phase()],
            outputs=[],
            updates=updates_op)

注意,输出层生成的原始动作位于[0.0, 1.0]范围内(使用 sigmoid 激活函数)。因此,我们添加另一个层级,该层级会针对每个动作维度将每个输出缩放到期望的范围。这样会针对任何给定状态向量生成确定性动作。稍后将向此动作添加噪点,以生成某个探索性行为。

另一个需要注意的是损失函数如何使用动作值(Q 值)梯度进行定义:

# Define loss function using action value (Q value) gradients
action_gradients = layers.Input(shape=(self.action_size,))
loss = K.mean(-action_gradients * actions)

这些梯度需要使用评论者模型计算,并在训练时提供梯度。因此指定为在训练函数中使用的“输入”的一部分:

self.train_fn = K.function(
   inputs=[self.model.input, action_gradients, K.learning_phase()],
    outputs=[],
    updates=updates_op)